Skip to content

feat: PROTO.SETFIELD and PROTO.DELFIELD for field-level mutations - #88

Merged
kacy merged 2 commits into
mainfrom
feat/proto-setfield-delfield
Feb 11, 2026
Merged

feat: PROTO.SETFIELD and PROTO.DELFIELD for field-level mutations#88
kacy merged 2 commits into
mainfrom
feat/proto-setfield-delfield

Conversation

@kacy

@kacy kacy commented Feb 10, 2026

Copy link
Copy Markdown
Owner

summary

adds two new commands for server-side field mutation of stored protobuf values:

  • PROTO.SETFIELD key field_path value — updates a single scalar field by parsing the raw string value based on the field's type descriptor (string, int32/64, uint32/64, float, double, bool, bytes, enum)
  • PROTO.DELFIELD key field_path — clears a field to its protobuf default value

both commands use a GET→decode→mutate→encode→SET pattern, reusing existing ProtoGet/ProtoSet shard requests. no changes to shard, keyspace, or persistence layers.

depends on #87 (PROTO.GETFIELD).

what was tested

  • unit tests for set_field (string, int32, bool), invalid value parsing, nonexistent field errors, and clear_field default reset (6 new tests in schema.rs)
  • command parse tests for PROTO.SETFIELD and PROTO.DELFIELD including wrong arity (4 new tests in command.rs)
  • integration tests in sharded mode: setfield_string, setfield_integer, setfield_bool, setfield_missing_key, setfield_wrong_type, setfield_nonexistent_field, setfield_invalid_value, delfield_clears_field, delfield_missing_key, delfield_returns_integer (10 new tests)
  • integration tests in concurrent mode: concurrent_setfield_string, concurrent_delfield_clears_field (2 new tests)
  • cargo clippy --workspace --features protobuf -- -D warnings clean
  • cargo check without protobuf feature (no regressions)
  • cargo fmt --check clean

design considerations

  • GET-mutate-SET pattern: field mutations fetch the current value, decode/mutate/re-encode server-side, then store back with XX flag (only if key still exists). this avoids adding new shard request types but means TTL is not preserved and concurrent mutations are non-atomic.
  • scalar-only restriction: repeated, map, and nested message fields return errors directing clients to use PROTO.SET for full replacement. this keeps the API surface clean and avoids ambiguous partial update semantics.
  • type-aware parsing: parse_field_value converts raw strings to typed protobuf values based on the field descriptor's Kind. bool accepts "true"/"false"/"1"/"0", enums accept names or numeric values.

Base automatically changed from feat/proto-getfield to main February 10, 2026 22:51
kacy added 2 commits February 10, 2026 20:29
adds server-side field mutation for stored protobuf values:

- PROTO.SETFIELD key field_path value — updates a single scalar field,
  parsing the raw string value based on the field's type descriptor.
  supports string, int32/64, uint32/64, float, double, bool, bytes,
  and enum fields. returns OK on success, Null for missing key.

- PROTO.DELFIELD key field_path — clears a field to its proto default.
  returns Integer(1) on success, Null for missing key.

both commands use a GET-decode-mutate-encode-SET pattern, routing
through existing ProtoGet/ProtoSet shard requests. no changes to
shard, keyspace, or persistence layers.

known limitations:
- TTL is not preserved (SETFIELD/DELFIELD reset it via ProtoSet)
- non-atomic: concurrent field mutations may cause lost updates
- scalars only: repeated, map, and message fields return errors

schema registry additions:
- set_field(), clear_field() public methods
- parse_field_value() for type-aware string parsing
- resolve_field_path_mut() for mutable nested path traversal

includes unit tests for all mutation paths and 12 new integration
tests across sharded and concurrent modes.
- replace unreachable!() with proper error returns in resolve_field_path
  and resolve_field_path_mut to eliminate potential panics
- replace .expect() with .ok_or_else() in resolve_field_path_mut
- handle u64 > i64::MAX in value_to_frame by falling back to bulk string
  instead of silently wrapping to negative via `as i64`
- add protobuf storage section to README with all 9 PROTO commands
- update command count from 85 to 94 and test count to 967
@kacy
kacy force-pushed the feat/proto-setfield-delfield branch from ab1219f to 5c7c860 Compare February 11, 2026 01:30
@kacy
kacy merged commit 150b81a into main Feb 11, 2026
5 of 7 checks passed
@kacy
kacy deleted the feat/proto-setfield-delfield branch February 11, 2026 01:32
kacy added a commit that referenced this pull request Feb 11, 2026
* feat: PROTO.SETFIELD and PROTO.DELFIELD for field-level mutations

adds server-side field mutation for stored protobuf values:

- PROTO.SETFIELD key field_path value — updates a single scalar field,
  parsing the raw string value based on the field's type descriptor.
  supports string, int32/64, uint32/64, float, double, bool, bytes,
  and enum fields. returns OK on success, Null for missing key.

- PROTO.DELFIELD key field_path — clears a field to its proto default.
  returns Integer(1) on success, Null for missing key.

both commands use a GET-decode-mutate-encode-SET pattern, routing
through existing ProtoGet/ProtoSet shard requests. no changes to
shard, keyspace, or persistence layers.

known limitations:
- TTL is not preserved (SETFIELD/DELFIELD reset it via ProtoSet)
- non-atomic: concurrent field mutations may cause lost updates
- scalars only: repeated, map, and message fields return errors

schema registry additions:
- set_field(), clear_field() public methods
- parse_field_value() for type-aware string parsing
- resolve_field_path_mut() for mutable nested path traversal

includes unit tests for all mutation paths and 12 new integration
tests across sharded and concurrent modes.

* fix: harden proto field ops and document protobuf commands

- replace unreachable!() with proper error returns in resolve_field_path
  and resolve_field_path_mut to eliminate potential panics
- replace .expect() with .ok_or_else() in resolve_field_path_mut
- handle u64 > i64::MAX in value_to_frame by falling back to bulk string
  instead of silently wrapping to negative via `as i64`
- add protobuf storage section to README with all 9 PROTO commands
- update command count from 85 to 94 and test count to 967
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant